package org.infrastructure.redis.service;

import javax.annotation.Resource;

import org.infrastructure.redis.IRedisHashService;
import org.infrastructure.redis.core.GsonRedisSerializer;
import org.springframework.context.annotation.Scope;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Service;

@Service
@Scope("prototype")
@SuppressWarnings("unchecked")
public class RedisHashServiceImpl<V> implements IRedisHashService<V> {
	private RedisTemplate<String, V> redisTemplate;
	private RedisSerializer<String> hkeySerializer;
	private RedisSerializer<V> hvalueSerializer;
	private RedisSerializer<String> serializer;

	@Resource(name = "redisTemplateHash")
	private void setRedisTemplate(final RedisTemplate<String, V> redisTemplateHash) {
		this.redisTemplate = redisTemplateHash;
		hkeySerializer = redisTemplate.getStringSerializer();
		hvalueSerializer = (RedisSerializer<V>) redisTemplate.getHashValueSerializer();
		serializer = redisTemplate.getStringSerializer();
		//System.err.println(hkeySerializer.getClass().getSimpleName());
	}

	@Override
	public void setValueClass(final Class<V> clz) {
		hvalueSerializer = new GsonRedisSerializer<V>(clz);
	}

	@Override
	public Boolean hSet(final String key, final String field, final V obj) {
		return redisTemplate.execute(new RedisCallback<Boolean>() {
			@Override
			public Boolean doInRedis(final RedisConnection connection) {
				return connection.hSet(serializer.serialize(key), hkeySerializer.serialize(field),
						hvalueSerializer.serialize(obj));
			}
		});
	}

	@Override
	public V hGet(final String key, final String field) {
		return redisTemplate.execute(new RedisCallback<V>() {
			@Override
			public V doInRedis(final RedisConnection connection) {
				final byte[] res = connection.hGet(serializer.serialize(key), hkeySerializer.serialize(field));
				if (res != null && res.length > 0) {
					return hvalueSerializer.deserialize(res);
				} else {
					return null;
				}
			}
		});
	}

	@Override
	public void hDel(final String key, final String field) {
		redisTemplate.execute(new RedisCallback<Long>() {
			@Override
			public Long doInRedis(final RedisConnection connection) {
				return connection.hDel(serializer.serialize(key), hkeySerializer.serialize(field));
			}
		});
	}

	@Override
	public boolean hExists(final String key, final String field) {
		return redisTemplate.execute(new RedisCallback<Boolean>() {
			@Override
			public Boolean doInRedis(final RedisConnection connection) {
				return connection.hExists(serializer.serialize(key), hkeySerializer.serialize(field));
			}
		});
	}

	@Override
	public long hLen(final String key) {
		return redisTemplate.execute(new RedisCallback<Long>() {
			@Override
			public Long doInRedis(final RedisConnection connection) {
				return connection.hLen(serializer.serialize(key));
			}
		});
	}

	@Override
	public long hIncrBy(final String key, final String field, final long number) {
		final Long result = redisTemplate.execute(new RedisCallback<Long>() {
			@Override
			public Long doInRedis(final RedisConnection connection) throws DataAccessException {
				return connection.hIncrBy(serializer.serialize(key), hkeySerializer.serialize(field), number);
			}
		});
		return result == null ? 0 : result;
	}

	@Override
	public long incr(final String key) {
		final Long result = redisTemplate.execute(new RedisCallback<Long>() {
			@Override
			public Long doInRedis(final RedisConnection connection) throws DataAccessException {
				final RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
				return connection.incr(serializer.serialize(key));
			}
		});
		return result == null ? 0 : result;
	}

	@Override
	public boolean delKey(final String key) {
		final Long result = redisTemplate.execute(new RedisCallback<Long>() {
			@Override
			public Long doInRedis(final RedisConnection connection) throws DataAccessException {
				return connection.del(serializer.serialize(key));
			}
		});
		return result > 0;
	}

}
